<!DOCTYPE html>
<html lang="en">
<head>
  <title>Egg and Koa - Born to build better enterprise frameworks and apps</title>
  <meta charset="utf-8">
  <meta name="description" content="index.description">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/images/favicon.png" type="image/x-icon">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
<link rel="stylesheet" href="/css/index.css">

    <script>
    !function(t,e,a,r,c){t.TracertCmdCache=t.TracertCmdCache||[],t[c]=window[c]||
      {_isInit:!0,call:function(){t.TracertCmdCache.push(arguments)},
      start:function(t){this.call('start',t)}},t[c].l=new Date;
      var n=e.createElement(a),s=e.getElementsByTagName(a)[0];
      n.async=!0,n.src=r,s.parentNode.insertBefore(n,s)}
    (window,document,'script','https://tracert.alipay.com/tracert.js','Tracert');
      Tracert.start({
        plugins: [ 'BucName' ],
        spmAPos: 'a454',
        spmBPos: 'b4893',
      });
    </script>
  
</head>
<body>
  <div class="nav" >
  <header>
    <a href="/en/" class="nav-logo leftpadding" alt="egg"><img src="https://zos.alipayobjects.com/rmsportal/VTcUYAaoKqXyHJbLAPyF.svg"></a>
    <ul class="nav-item">
      <li>
        <form id="search-form">
          <input type="text" id="search-query" class="search-query st-default-search-input">
        </form>
      </li>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/intro/egg-and-koa.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/intro/egg-and-koa.html" >中文</a></li></ul>
        </li>
      
      <li><iframe src="https://ghbtns.com/github-btn.html?user=eggjs&repo=egg&type=star&count=true" frameborder="0" scrolling="0" width="150px" height="20px"></iframe></li>
    </ul>
    <a id="mobileTrigger" href="#" class="mobile-trigger">
      <ul>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </a>
  </header>
</div>
  <div id="container" class="container">
    <div class="page-main">
  <article class="markdown-body">
    <h1>Egg and Koa</h1>
    <h2 id="asynchronous-programming-model"><a class="markdown-anchor" href="#asynchronous-programming-model">#</a> Asynchronous programming model</h2>
<p>Node.js is an asynchronous world, asynchronous programming models in official API support are all in callback form ，it brings many problems. For example:</p>
<ul>
<li><a href="http://callbackhell.com/" target="_blank" rel="noopener">callback hell</a>: Notorious &quot;callback hell&quot;。</li>
<li><a href="https://oren.github.io/blog/zalgo.html" target="_blank" rel="noopener">release zalgo</a>: Asynchronous functions may call callback function response data synchronously which would bring inconsistency.</li>
</ul>
<p>The community has provided many solutions for the problems, the winner is Promise, it is built into ECMAScript 2015. On the basis of Promise, and with the ability of Generator to switch context, we can write asynchronous code in synchronous way with <a href="https://github.com/tj/co" target="_blank" rel="noopener">co</a> and other third party libraries. Meanwhile <a href="https://github.com/tc39/ecmascript-asyncawait" target="_blank" rel="noopener">async function</a>, the official solution has been published in ECMAScript 2017 and landed in Node.js 8.</p>
<h3 id="async-function"><a class="markdown-anchor" href="#async-function">#</a> Async function</h3>
<p><a href="https://github.com/tc39/ecmascript-asyncawait" target="_blank" rel="noopener">Async function</a> is a syntactic sugar at the language level. In async function, we can use <code>await</code> to wait for a promise to be resolved(or rejected, which will throw an exception), and Node.js LTS (8.x) has supported this feature.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> fn = <span class="keyword">async</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> user = <span class="keyword">await</span> getUser();</span><br><span class="line">  <span class="keyword">const</span> posts = <span class="keyword">await</span> fetchPosts(user.id);</span><br><span class="line">  <span class="keyword">return</span> &#123; user, posts &#125;;</span><br><span class="line">&#125;;</span><br><span class="line">fn().then(<span class="function"><span class="params">res</span> =&gt;</span> <span class="built_in">console</span>.log(res)).catch(<span class="function"><span class="params">err</span> =&gt;</span> <span class="built_in">console</span>.error(err.stack));</span><br></pre></td></tr></table></figure>
<h2 id="koa"><a class="markdown-anchor" href="#koa">#</a> Koa</h2>
<blockquote>
<p>Koa is a new Web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for Web applications and APIs.</p>
</blockquote>
<p>The design styles of Koa and Express are very similar, The underlying basic library is the same, <a href="https://github.com/jshttp" target="_blank" rel="noopener">HTTP library</a>. There are several significant differences between them. Besides the asynchronous solution by default mentioned above, there are the following points.</p>
<h3 id="midlleware"><a class="markdown-anchor" href="#midlleware">#</a> Midlleware</h3>
<p>The middleware in Koa is different from Express, Koa use the onion model:</p>
<ul>
<li>Middleware onion diagram:</li>
</ul>
<p><img src="https://camo.githubusercontent.com/d80cf3b511ef4898bcde9a464de491fa15a50d06/68747470733a2f2f7261772e6769746875622e636f6d2f66656e676d6b322f6b6f612d67756964652f6d61737465722f6f6e696f6e2e706e67" alt=""></p>
<ul>
<li>Middleware execution sequence diagram:</li>
</ul>
<p><img src="https://raw.githubusercontent.com/koajs/koa/a7b6ed0529a58112bac4171e4729b8760a34ab8b/docs/middleware.gif" alt=""></p>
<p>All the requests will be executed twice during one middleware. Compared to Express middleware, it is very easy to implement post-processing logic. You can obviously feel the advantage of Koa middleware model by comparing the compress middleware implementing in Koa and Express.</p>
<ul>
<li><a href="https://github.com/koajs/compress/blob/master/index.js" target="_blank" rel="noopener">koa-compress</a> for Koa.</li>
<li><a href="https://github.com/expressjs/compression/blob/master/index.js" target="_blank" rel="noopener">compression</a> for Express.</li>
</ul>
<h3 id="context"><a class="markdown-anchor" href="#context">#</a> Context</h3>
<p>Unlike that there are only two objects <code>Request</code> and <code>Response</code> in Express, Koa has one more, <code>Context</code> object in one HTTP request(it is <code>this</code> in Koa 1, while it is the first parameter for middleware function in Koa 2). We can mount all the related properties in one request to this object. Such as <a href="https://github.com/eggjs/egg-tracer/blob/1.0.0/lib/tracer.js#L12" target="_blank" rel="noopener">traceId</a> that runs through the whole request lifetime (which will be called anywhere afterward) could be mounted. It is more semantic other than request and response.</p>
<p>At the same time Request and Response are mounted to Context object. Just like Express, the two objects provide lots of easy ways to help developing. For example:</p>
<ul>
<li><code>get request.query</code></li>
<li><code>get request.hostname</code></li>
<li><code>set response.body</code></li>
<li><code>set response.status</code></li>
</ul>
<h3 id="exception-handlering"><a class="markdown-anchor" href="#exception-handlering">#</a> Exception handlering</h3>
<p>Another enormous advantage for writing asynchronous code in synchronous way is that it is quite at ease to handle exception. You can catch all the exceptions thrown in the codes followed the convention with <code>try catch</code>. We can easily write a customized exception handling middleware.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">onerror</span>(<span class="params">ctx, next</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">await</span> next();</span><br><span class="line">  &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">    ctx.app.emit(<span class="string">'error'</span>, err);</span><br><span class="line">    ctx.body = <span class="string">'server error'</span>;</span><br><span class="line">    ctx.status = err.status || <span class="number">500</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Putting this middleware before others, you can catch all the exceptions thrown by the synchronous or asynchronous code.</p>
<h2 id="egg-inherits-from-koa"><a class="markdown-anchor" href="#egg-inherits-from-koa">#</a> Egg inherits from Koa</h2>
<p>As described above, Koa is an excellent framework. However, it is not enough to build an enterprise-class application.</p>
<p>Egg is built around the Koa. On the basis of Koa model, Egg implements enhancements one step further.</p>
<h3 id="extension"><a class="markdown-anchor" href="#extension">#</a> Extension</h3>
<p>In the framework or application based on Egg, we can extend the prototype of 4 Koa objects by defining <code>app/extend/{application,context,request,response}.js</code>. With this, we can write more utility methods quickly. For example, we have the following code in <code>app/extend/context.js</code>:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// app/extend/context.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  get isIOS() &#123;</span><br><span class="line">    <span class="keyword">const</span> iosReg = <span class="regexp">/iphone|ipad|ipod/i</span>;</span><br><span class="line">    <span class="keyword">return</span> iosReg.test(<span class="keyword">this</span>.get(<span class="string">'user-agent'</span>));</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>It can be used in controller then:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// app/controller/home.js</span></span><br><span class="line">exports.handler = <span class="function"><span class="params">ctx</span> =&gt;</span> &#123;</span><br><span class="line">  ctx.body = ctx.isIOS</span><br><span class="line">    ? <span class="string">'Your operating system is iOS.'</span></span><br><span class="line">    : <span class="string">'Your operating system is not iOS.'</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>More about extension, please check <a href="../basics/extend.html">Exception</a> section.</p>
<h3 id="plugin"><a class="markdown-anchor" href="#plugin">#</a> Plugin</h3>
<p>As is known to all, Many middlewares are imported to provide different kind of features in Express and Koa. Eg, <a href="https://github.com/koajs/session" target="_blank" rel="noopener">koa-session</a> provides the Session support, <a href="https://github.com/koajs/bodyparser" target="_blank" rel="noopener">koa-bodyparser</a> help to parse request body. Egg has provided a powerful plugin mechanism to make it easier to write stand alone features.</p>
<p>One plugin can include:</p>
<ul>
<li>extend：extend the context of base object, provide utility and attributes.</li>
<li>middleware：add one or more middlewares, provide pre or post processing logic for request.</li>
<li>config：configure the default value in different environments.</li>
</ul>
<p>Stand alone module plugin can provide rich features with high maintenancability. You can almost forget the configuration as the plugin supports configuring the default value in different environments.</p>
<p><a href="https://github.com/eggjs/egg-security" target="_blank" rel="noopener">egg-security</a> is a typical example.</p>
<p>More about plugin, please check <a href="../basics/plugin.html">Plugin</a> section.</p>
<h3 id="roadmap"><a class="markdown-anchor" href="#roadmap">#</a> Roadmap</h3>
<h4 id="egg-1x"><a class="markdown-anchor" href="#egg-1x">#</a> Egg 1.x</h4>
<p>When Egg 1.x released, the Node.js LTS version did not support async function，so Egg 1.x was based on Koa 1.x. On the basis of this, Egg had added fully async function support. Egg is completely compatible with middlewares in Koa 2.x, all applications could write with <code>async function</code>.</p>
<ul>
<li>The underlying is based on Koa 1.x, asynchronous solution is based on generator function wrapped by <a href="https://github.com/tj/co" target="_blank" rel="noopener">co</a>.</li>
<li>Official plugin and core of Egg are written in generator function,  keep supporting Node.js LTS version, use <a href="https://github.com/tj/co" target="_blank" rel="noopener">co</a> when necessary to be compatiable with async function.</li>
<li>Application developers can choose either async function (Node.js 8.x+) or generator function (Node.js 6.x+).</li>
</ul>
<h4 id="egg-2x"><a class="markdown-anchor" href="#egg-2x">#</a> Egg 2.x</h4>
<p>When Node.js 8 became LTS version, async function could be used in Node.js without any performance problem. Egg released 2.x based on Koa 2.x, the framework and built-in plugins were all written by async function, and Egg 2.x still kept compatibility with generator function and all the usages in Egg 1.x, applications based on Egg 1.x can migrate to Egg 2.x only by upgrading to Node.js 8.</p>
<ul>
<li>The underlying will be based on Koa 2.x, asynchronous solution will be based on async function.</li>
<li>Official plugin and core of egg will be written in async function.</li>
<li>Recommend user to transfer business layer to async function.</li>
<li>Only support Node.js 8+.</li>
</ul>

  </article>
  <aside id="mobileAside" class="toc">
  <div class="mobile-menu">
    <ul>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/intro/egg-and-koa.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/intro/egg-and-koa.html" >中文</a></li></ul>
        </li>
      
    </ul>
  </div>
  <dl><dt id="title-Intro" style="cursor: pointer;" class="aside-title">Guide<a id="collapse-icon-Intro" class="icon opend"></a></dt><dd id=panel-Intro><ul><li><a href="/en/intro/index.html" class="menu-link">What is Egg?</a></li><li><a href="/en/intro/egg-and-koa.html" class="menu-link">Egg and Koa</a></li><li><a href="/en/intro/quickstart.html" class="menu-link">Quick Start</a></li><li><a href="/en/tutorials/progressive.html" class="menu-link">Progressive</a></li><li><a href="/en/migration.html" class="menu-link">Migration to 2.x</a></li></ul></dd><dt id="title-Basics" style="cursor: pointer;" class="aside-title">Basis Function<a id="collapse-icon-Basics" class="icon opend"></a></dt><dd id=panel-Basics><ul><li><a href="/en/basics/structure.html" class="menu-link">Directory Structure</a></li><li><a href="/en/basics/objects.html" class="menu-link">Built-in Objects</a></li><li><a href="/en/basics/env.html" class="menu-link">Environment</a></li><li><a href="/en/basics/config.html" class="menu-link">Configuration</a></li><li><a href="/en/basics/middleware.html" class="menu-link">Middleware</a></li><li><a href="/en/basics/router.html" class="menu-link">Router</a></li><li><a href="/en/basics/controller.html" class="menu-link">Controller</a></li><li><a href="/en/basics/service.html" class="menu-link">Service</a></li><li><a href="/en/basics/plugin.html" class="menu-link">Plugin</a></li><li><a href="/en/basics/schedule.html" class="menu-link">Schedule</a></li><li><a href="/en/basics/extend.html" class="menu-link">Extend</a></li><li><a href="/en/basics/app-start.html" class="menu-link">Custom Init</a></li></ul></dd><dt id="title-Core" style="cursor: pointer;" class="aside-title">Core<a id="collapse-icon-Core" class="icon opend"></a></dt><dd id=panel-Core><ul><li><a href="/en/core/development.html" class="menu-link">Development</a></li><li><a href="/en/core/unittest.html" class="menu-link">Unit Testing</a></li><li><a href="/en/core/deployment.html" class="menu-link">Deployment</a></li><li><a href="/en/core/logger.html" class="menu-link">Logger</a></li><li><a href="/en/core/httpclient.html" class="menu-link">HttpClient</a></li><li><a href="/en/core/cookie-and-session.html" class="menu-link">Cookie and Session</a></li><li><a href="/en/core/cluster-and-ipc.html" class="menu-link">Cluster and IPC</a></li><li><a href="/en/core/view.html" class="menu-link">View</a></li><li><a href="/en/core/error-handling.html" class="menu-link">Error Handling</a></li><li><a href="/en/core/security.html" class="menu-link">Security</a></li><li><a href="/en/core/i18n.html" class="menu-link">i18n</a></li></ul></dd><dt id="title-Tutorials" style="cursor: pointer;" class="aside-title">Tutorials<a id="collapse-icon-Tutorials" class="icon opend"></a></dt><dd id=panel-Tutorials><ul><li><a href="/en/tutorials/mysql.html" class="menu-link">MySQL</a></li><li><a href="/en/tutorials/restful.html" class="menu-link">RESTful API</a></li><li><a href="/en/tutorials/passport.html" class="menu-link">Passport</a></li><li><a href="/en/tutorials/socketio.html" class="menu-link">Socket.IO</a></li><li><a href="/en/tutorials/assets.html" class="menu-link">Assets</a></li><li><a href="/en/tutorials/typescript.html" class="menu-link">TypeScript</a></li></ul></dd><dt id="title-Advanced" style="cursor: pointer;" class="aside-title">Advanced<a id="collapse-icon-Advanced" class="icon opend"></a></dt><dd id=panel-Advanced><ul><li><a href="/en/advanced/loader.html" class="menu-link">Loader</a></li><li><a href="/en/advanced/plugin.html" class="menu-link">Plugin Development</a></li><li><a href="/en/advanced/framework.html" class="menu-link">Framework</a></li><li><a href="/en/advanced/cluster-client.html" class="menu-link">Cluster Enhancement</a></li><li><a href="/en/advanced/view-plugin.html" class="menu-link">View Plugin</a></li><li><a href="/en/style-guide.html" class="menu-link">Style Guide</a></li></ul></dd><dt id="title-Community" style="cursor: pointer;" class="aside-title">Community<a id="collapse-icon-Community" class="icon opend"></a></dt><dd id=panel-Community><ul><li><a href="/en/plugins/" class="menu-link">Plugin List</a></li><li><a href="/en/contributing.html" class="menu-link">Contributing</a></li><li><a href="/en/resource.html" class="menu-link">Resource</a></li><li><a href="/en/faq.html" class="menu-link">FAQ</a></li></ul></dd></dl>
</aside>
<script>
var mobileTrigger = document.getElementById('mobileTrigger');
var mobileAside = document.getElementById('mobileAside');

var expandMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon opend';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = '';
  }
}

var collapseMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon closed';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = 'aside-panel-hidden';
  }
}

mobileAside.onclick = function(e) {
  const targetId = e.target.id;
  if (targetId && (targetId.indexOf('title-') > -1 || targetId.indexOf('collapse-icon-') > -1)) {
    const title = targetId.replace('title-', '').replace('collapse-icon-', '');
    try { 
      // the the browser may have no localStroage or JSON.parse may throw exception.
      const menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
        
      // current menu status
      const curClosed = menuInfo[title] ? menuInfo[title].closed : false; // default false

      // change UI
      curClosed ? expandMenu(title) : collapseMenu(title);

      // save menuInfo to localStorage
      menuInfo[title] = { closed: !curClosed } // opposite
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    } catch (e) {}
  }
};

mobileTrigger.onclick = function(e) {
  e.preventDefault();
  if (mobileAside.className.indexOf('mobile-show') === -1) {
    mobileAside.className += ' mobile-show';
  } else {
    mobileAside.className = 'toc';
  }
};

(function() {
  // save data to localStorage because the page will refresh when user change the url.
  let menuInfo;
  try { 
    // the the browser may have no localStroage or JSON.parse may throw exception.
    menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
    if (!menuInfo) {
      menuInfo = {};
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    }
  } catch (e) {
    menuInfo = {}; // default {}
  }

  for (const title in menuInfo) {
    if (menuInfo[title] && menuInfo[title].closed) { // menu in closed status.
      collapseMenu(title);
    } else {
      expandMenu(title);
    }
  }

  // highlight menu
  const pathname = window.location.pathname;
  const selector = `a[href="${pathname}"].menu-link,a[href="${pathname}index.html"].menu-link`;
  const menuItem = mobileAside.querySelector(selector);
  if (menuItem) { menuItem.className += ' highlight'; }
})();
</script>

</div>

  </div>
</body>
<script src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
<script>
docsearch({
  apiKey: '1561de31a86f79507ea00cdb54ce647c',
  indexName: 'eggjs',
  inputSelector: '#search-query',
});
</script>
<div class="cnzz">
<script src="https://s11.cnzz.com/z_stat.php?id=1261142226&web_id=1261142226" language="JavaScript"></script>
</div>

</html>
